package com.dragon.www.haier.net;

import android.content.Context;
import android.net.DhcpInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2015/6/12.
 */
public class WIFIUtils {

    public static final String WIFI_AP_STATE_CHANGED_ACTION =
            "android.net.wifi.WIFI_AP_STATE_CHANGED";

    public static final String EXTRA_WIFI_AP_STATE = "wifi_state";

    public static final int WIFI_AP_STATE_DISABLING = 10;

    public static final int WIFI_AP_STATE_DISABLED = 11;

    public static final int WIFI_AP_STATE_ENABLING = 12;

    public static final int WIFI_AP_STATE_ENABLED = 13;

    public static final int WIFI_AP_STATE_FAILED = 14;

    private final static String TAG = "WIFIUtils";
    private final static Pattern IPV4_PATTERN = Pattern.compile("^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
            + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$");
    private WifiManager wifiManager;

    /**
     * 按照IP获取广播地址
     *
     * @param wifiManager
     * @return
     * @throws UnknownHostException
     */
    public static InetAddress getBroadcastAddress(WifiManager wifiManager) throws UnknownHostException {
        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
        if (dhcpInfo == null) {
            return InetAddress.getByName("255.255.255.255");
        }
        int broadcast = (dhcpInfo.ipAddress & dhcpInfo.netmask) | ~dhcpInfo.netmask;
        return InetAddress.getByAddress(Utils.int2LHbyte(broadcast));
    }

    public static SocketAddress getBroadcastAddress(WifiManager wifiManager, int port) throws UnknownHostException {
        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
        if (dhcpInfo == null) {
            return new InetSocketAddress(InetAddress.getByName("255.255.255.255"), port);
        }
        int broadcast = (dhcpInfo.ipAddress & dhcpInfo.netmask) | ~dhcpInfo.netmask;
        return new InetSocketAddress(InetAddress.getByAddress(Utils.int2LHbyte(broadcast)), port);
    }

    public static boolean existActiveWifi(WifiInfo wifiInfo) {
        if (wifiInfo != null && wifiInfo.getSSID() != null && !wifiInfo.getSSID().equals("0x")
                && wifiInfo.getNetworkId() != -1) {
            return true;
        }
        return false;
    }


    public static boolean isWifiApEnabled(WifiManager wifiManager) {
        if (wifiManager == null)
            throw new NullPointerException("Please check. WifiManger is NULL");
        try {
            Method isWifiApEnabled = WifiManager.class.getMethod("isWifiApEnabled");
            return (Boolean) isWifiApEnabled.invoke(wifiManager);
        } catch (Exception e) {
            Log.e(TAG, "Cannot isWifiApEnabled", e);
            return false;
        }
    }

    public static WifiConfiguration getWifiApConfiguration(WifiManager wifiManager) {
        if (wifiManager == null)
            throw new NullPointerException("Please check. WifiManger is NULL");
        try {
            Method getWifiApConfiguration = WifiManager.class.getMethod("getWifiApConfiguration");
            return (WifiConfiguration) getWifiApConfiguration.invoke(wifiManager);
        } catch (Exception e) {
            Log.e(TAG, "Cannot WifiConfiguration", e);
            return null;
        }
    }

    public static boolean setWifiApEnabled(WifiManager wifiManager, WifiConfiguration config, boolean enabled) {
        if (wifiManager == null)
            throw new NullPointerException("Please check. WifiManger is NULL");
        try {
            Method setWifiApEnabled = WifiManager.class.getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
            return (Boolean) setWifiApEnabled.invoke(wifiManager, config, enabled);
        } catch (Exception e) {
            Log.e(TAG, "Cannot setWifiApEnabled", e);
            return false;
        }
    }


    private static String formatIpAddress(int ipAdress) {
        return (ipAdress & 0xFF) + "." +
                ((ipAdress >> 8) & 0xFF) + "." +
                ((ipAdress >> 16) & 0xFF) + "." +
                (ipAdress >> 24 & 0xFF);
    }

    private static void setWifiIP(InetAddress addr, int length, WifiConfiguration config)
            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
            UnknownHostException, InvocationTargetException, InstantiationException {
        Object linkProperties = getField(config, "linkProperties");
        if (linkProperties == null)
            return;
        Class<?> address = Class.forName("android.net.LinkAddress");
        Constructor<?> addressConstructor = address.getConstructor(new Class[]{InetAddress.class, int.class});
        Object addressObj = addressConstructor.newInstance(addr, length);
        ArrayList list = (ArrayList) getDeclaredField(linkProperties, "mLinkAddresses");
        list.clear();
        list.add(addressObj);
    }

    private static void setWifiGateway(InetAddress gateway, WifiConfiguration config)
            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
            UnknownHostException, InvocationTargetException, InstantiationException {
        Object linkProperties = getField(config, "linkProperties");
        if (linkProperties == null) return;
        Class route = Class.forName("android.net.RouteInfo");
        Constructor routeConstructor = route.getConstructor(new Class[]{InetAddress.class});
        Object routeInfo = routeConstructor.newInstance(gateway);
        ArrayList routes = (ArrayList) getDeclaredField(linkProperties, "mRoutes");
        routes.clear();
        routes.add(routeInfo);
    }

    private static void setWifiDNS(InetAddress dns, WifiConfiguration config)
            throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
            UnknownHostException, InvocationTargetException, InstantiationException {
        Object linkProperties = getField(config, "linkProperties");
        if (linkProperties == null) return;
        ArrayList routes = (ArrayList) getDeclaredField(linkProperties, "mDnses");
        routes.clear();
        routes.add(dns);
    }

    private static void setEnumField(Object obj, String value, String name)
            throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getField(name);
        f.set(obj, Enum.valueOf((Class<Enum>) f.getType(), value));
    }

    private static void setIpAssignment(String type, WifiConfiguration config)
            throws IllegalAccessException, NoSuchFieldException {
        setEnumField(config, type, "ipAssignment");
    }

    /**
     * @param IP  IP��ַ
     * @param GW  ����
     * @param DNS
     * @throws Exception
     */
    public static void setStaticIP(WifiManager wifiManager, String IP, String GW, String DNS) throws Exception {
        if (wifiManager == null)
            throw new Exception("Please check. WifiManger is NULL");
        List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
        for (WifiConfiguration config : configs) {
            if (wifiManager.getConnectionInfo().getNetworkId()
                    == config.networkId) {
                try {
                    if (IP != null)
                        setWifiIP(InetAddress.getByName(IP), 24, config);
                    if (GW != null)
                        setWifiGateway(InetAddress.getByName(GW), config);
                    if (DNS != null)
                        setWifiDNS(InetAddress.getByName(DNS), config);
                    wifiManager.updateNetwork(config);
                    wifiManager.saveConfiguration();
                } catch (Exception e) {
                    Log.e("selfActivity", e.getMessage());
                    throw e;
                }
            }
        }
    }

    /**
     * 获取IP
     *
     * @return
     */
    public static String getLocalIPAddr() {
        try {
            for (Enumeration<NetworkInterface> temp = NetworkInterface.getNetworkInterfaces(); temp.hasMoreElements(); ) {
                NetworkInterface networkInterface = temp.nextElement();
                for (Enumeration<InetAddress> addr = networkInterface.getInetAddresses(); addr.hasMoreElements(); ) {
                    InetAddress inet = addr.nextElement();
                    if (!inet.isLoopbackAddress() &&
                            isValidIp4Address(inet.getHostAddress())) {
                        return inet.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            Log.e(TAG, "Get LocalAddr Failed...");
        }
        return null;
    }

    public static String getLocalWIFIIPAddr(Context context) {
        DhcpInfo dhcp = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getDhcpInfo();
        return parseLong(dhcp.ipAddress);
    }

    /**
     * 获取网关
     *
     * @param context
     * @return
     */
    public final static String getLocalGateWayAddress(Context context) {
        DhcpInfo dhcp = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getDhcpInfo();
        return parseLong(dhcp.gateway);
    }

    /**
     * 获取子网掩码
     *
     * @param context
     * @return
     */
    public final static String getLocalMaskAddress(Context context) {
        DhcpInfo dhcp = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getDhcpInfo();
        return parseLong(dhcp.netmask);
    }

    public final static boolean isIPv4Address(String ip) {
        return IPV4_PATTERN.matcher(ip).matches();
    }

    private static String parseLong(long d) {
        StringBuffer sb = new StringBuffer();
        sb.append(String.valueOf((int) (d & 0xff)));
        sb.append('.');
        sb.append(String.valueOf((int) ((d >> 8) & 0xff)));
        sb.append('.');
        sb.append(String.valueOf((int) ((d >> 16) & 0xff)));
        sb.append('.');
        sb.append(String.valueOf((int) ((d >> 24) & 0xff)));
        return sb.toString();
    }

    private static Object getDeclaredField(Object obj, String name)
            throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getDeclaredField(name);
        f.setAccessible(true);
        return f.get(obj);
    }

    private static Object getField(Object obj, String name) throws SecurityException,
            NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field f = obj.getClass().getField(name);
        Object out = f.get(obj);
        return out;
    }


    public static boolean isValidIp4Address(final String hostName) {
        try {
            return Inet4Address.getByName(hostName) != null;
        } catch (UnknownHostException ex) {
            return false;
        }
    }

    public static boolean isValidIp6Address(final String hostName) {
        try {
            return Inet6Address.getByName(hostName) != null;
        } catch (UnknownHostException ex) {
            return false;
        }
    }

    public void checkWifi(boolean checked) throws Exception {
        if (wifiManager == null)
            throw new Exception("Please check. WifiManger is NULL");
        if (wifiManager.isWifiEnabled() != checked) {
            wifiManager.setWifiEnabled(checked);
        }

        if (checked) {
            while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
                Thread.sleep(1000);
            }
            if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
                Log.i(TAG, "Wifi Enabled Now...");
            }
        } else {
            while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLING) {
                Thread.sleep(1000);
            }
            if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
                Log.i(TAG, "Wifi Disabled Now...");
            }
        }
    }
}
